#!/usr/local/bin/python2.4

import icon
import string
import sys

# The board represented as N rows, 2N-1 SW-NE slanting diagonals and 
# 2N - 1 NW-SE slanting diagonals

class Board:
    def __init__(self, N):
        self.N = N
        self.clear()

    def clear(self):
        self.up = [0 for _ in xrange(0, 2 * self.N)]
        self.down = [0 for _ in xrange(0, 2 * self.N)]
        self.row = [0 for _ in xrange(0, self.N + 1)]

    def not_attacked(self, r, c):
        return self.row[r] == self.down[r + c - 1] == self.up[self.N + r - c] == 0

    # This function is only going to yield at most one value: the first free row.
    # When it's resumed, it will clear the row and return.
    # I don't have a way to automatically perform data backtracking
    def place(self, r, c):
        if self.not_attacked(r, c):
            self.row[r] = self.down[r + c - 1] = self.up[self.N + r - c] = r
            yield r
            self.row[r] = self.down[r + c - 1] = self.up[self.N + r - c] = 0

    # Yield a sequence of the legal rows for a queen in column c
    def q(self, c):
        return icon.apply(lambda r: self.place(r, c), xrange(1, self.N + 1))


# The write function, which receives row positions as an argument tuple
def write(*rows):
    print string.join(map(str, rows), " ")


# An example call with 8 queens on an 8x8 board
def test8():
    board = Board(8)
    print "Arrangements of 8 queens"
    icon.every_do(write, board.q(1), board.q(2), \
                  board.q(3), board.q(4), board.q(5), \
                  board.q(6), board.q(7), board.q(8))

# Variable size boards
def test(N):
    board = Board(N)
    # The automated way of passing N board.q(i) arguments
    args = tuple(map(lambda i: board.q(i), range(1, N + 1)))

    # Write out the first solution
    print "One arrangement of %d queens" % N
    icon.first_do(write, *args)

    # Clear the board and write all legal arrangements of 8 queens
    board.clear()
    print
    print "All arrangements of %d queens" % N
    icon.every_do(write, *args)


if len(sys.argv) > 1:
    test(int(sys.argv[1]))
else:
    test8()
